home *** CD-ROM | disk | FTP | other *** search
- /*
- File: Undo.cpp
-
- Contains: Implementation for Undo class
-
- Owned by: Nick Pilch
-
- Copyright: © 1994 - 1996 by Apple Computer, Inc., all rights reserved.
-
- Change History (most recent first):
-
- <3> .04.1996 NP 1316777: Partiall fix race condition with
- the disposal notification process.
- <24> 10/8/95 TJ Fixes Recomended by Refball
- <23> 9/11/95 NP 1272294: Messaging code cleanup.
- <22> 8/26/95 TÇ 1274606 FB2: Patching Remarks
- <21> 8/23/95 NP 1275237, 1267015: Support for aborting
- transactions.
- <20> 8/22/95 eeh 1276821:
- kOpenDocShellSignature->kODShellSignature
- <19> 8/16/95 NP 1275241: IDL Review. Remove unnecessary
- overrides.
- <18> 8/12/95 TÇ 1276806 Optimization: use kODFalse instead
- of kODTrue in comparisons
- <17> 8/7/95 NP 1269965: should be able to nest
- transactions, 1269789: Transaction redo
- incorrectly implemented.
- <16> 8/3/95 RR #1257260: Collapse B classes. Remove
- somInit methods. Don't call IsInitialized
- or SubclassResponsibility
- <15> 7/26/95 DM #1270320: Memory leak fixes: dispose descs
- in NotifyUndoOrRedoOrDispose
- <14> 6/16/95 TJ Uncommented the pragma export_lib on.
- <13> 6/15/95 NP 1237542: Fix CORBA memory stuff, 1249152:
- Undo not respecting marks
- <12> 5/26/95 RR #1251403: Multithreading naming support
- <11> 5/21/95 NP 1249290: Fix crash if libraries are
- preloaded.
- <10> 5/3/95 NP 1211084: Remove 5$
- <9> 4/28/95 NP 1223103: Logic error in Undo. 1243568,
- 1209554: use of ODGetSystemHeap.
- <8> 4/26/95 NP 1243568: Don't use ODSystemHeap.
- <7> 4/14/95 NP 1238258: Don't use OrderedCollection, use a
- collection class that has no virtual
- methods and that uses no classes with
- virtual methods.
- <6> 4/14/95 NP 1217965: Destroy all system objects when
- last doc is closed.
- <5> 1/26/95 eeh 1213354: ODActionData now an ODByteArray.
- <4> 1/25/95 jpa New ODIText format [1212619]
- <3> 12/25/94 TÇ 1191189 Eliminate duplicate Def.h, Def.xh
- files
- <2> 9/29/94 RA 1189812: Mods for 68K build.
- <1> 7/27/94 NP first checked in
-
- To Do:
- Remove destructors where not needed.
-
- */
-
-
- #ifndef _PART_
- #include "Part.xh"
- #endif
-
- //#ifndef _ORDCOLL_
- //#include "OrdColl.h"
- //#endif
-
- #ifndef SOM_Module_OpenDoc_StdDefs_defined
- #include "StdDefs.xh"
- #endif
-
- #ifndef _SEUTILS_
- #include "SEUtils.h"
- #endif
-
- #ifndef _ODUTILS_
- #include "ODUtils.h"
- #endif
-
- #ifndef _ITEXT_
- #include "IText.h"
- #endif
-
- #define ODUndo_Class_Source
- #define VARIABLE_MACROS
- #include <Undo.xih>
-
- #ifndef _EXCEPT_
- #include <Except.h>
- #endif
-
- #ifndef _BARRAY_
- #include <BArray.h>
- #endif
-
- //#ifndef _ODNEW_
- //#include <ODNew.h>
- //#endif
-
- #ifndef _ODDEBUG_
- #include "ODDebug.h"
- #endif
-
- //#ifndef _ODTYPES_
- //#include "ODTypes.h"
- //#endif
-
- //#ifndef _PLFMDEF_
- //#include "PlfmDef.h"
- //#endif
-
- //#ifndef _LIST_
- //#include "List.h"
- //#endif
-
- #ifndef _ODMEMORY_
- #include "ODMemory.h"
- #endif
-
- #ifndef __ERRORS__
- #include <Errors.h>
- #endif
-
- #ifndef _ODDEBUG_
- #include "ODDebug.h"
- #endif
-
- #ifndef _TEMPOBJ_
- #include <TempObj.h>
- #endif
-
- #pragma segment ODUndo
-
- /*
- IMPLEMENTATION NOTES
-
- System Heap allocations
-
- Almost all memory allocations occur in the system heap.
-
- I'm trying to use as little system heap memory as possible because putting
- pointers into the system heap could be a bad idea (mem fragmentation).
-
- UNDO AND REDO STACKS
-
- The stacks are implemented with the UndoOrderedCollection class. The first item
- in the collection represents the top of the stack.
-
- MARKING
-
- When asked to mark a stack that is empty, nothing is done. The code that removes
- actions from a stack up to the last mark simply stops when it comes to the end
- of a stack.
-
- ADDCLIENT, ETC.
-
- We need to use these functions to ensure the SystemUndo is freed when
- the last OD document is closed. The memory associated with it will have gone
- away.
- */
-
- //==============================================================================
- // Special new operator for the system heap that use NewPtrSys and
- // DisposePtr.
- //==============================================================================
-
- enum ODUndoMemoryAllocation
- {
- kODSystemHeap
- };
-
- void* operator new(size_t size, ODUndoMemoryAllocation allocation);
-
- void* operator new(size_t size, ODUndoMemoryAllocation allocation)
- {
- void* retVal;
-
- if (allocation == kODSystemHeap)
- retVal = NewPtrSys(size);
- else
- THROW(kODErrNotImplemented);
-
- return retVal;
- }
-
- //==============================================================================
- // Temporarily include new UndoOrderedCollection class that I can allocate in the
- // system heap. (May be longer than temporary.)
- //==============================================================================
-
-
-
- /////////////// BEGIN TEMP HACK
-
-
-
- //==============================================================================
- // UndoLink
- //==============================================================================
-
- class UndoLink {
- public:
- // void* operator new(size_t size) {return NewPtrSys(size);}
- void operator delete(void* ptr) {DisposePtr((Ptr)ptr);}
- UndoLink();
-
- UndoLink(UndoLink* next, UndoLink* previous);
-
- UndoLink( const UndoLink& );
-
- ~UndoLink();
-
- UndoLink* GetNext() const {return fNext;}
-
- UndoLink* GetPrevious() const {return fPrevious;}
-
- // The following operations are provided for efficiency, but DO NOT USE THEM
- // if there are any iterators active on a list. These operations don't bump
- // the list's fSeed and the iterators will not be able to detect that they
- // are out of sync!
-
- void Remove( );
-
- void AddBefore( UndoLink *aLink );
-
- void AddAfter( UndoLink *aLink );
-
- //private-by-convention:
-
- void SetNext(UndoLink* aLink) {fNext = aLink;}
-
- void SetPrevious(UndoLink* aLink) {fPrevious = aLink;}
-
- private:
-
- UndoLink* fNext;
- UndoLink* fPrevious;
- };
-
-
- //==============================================================================
- // UndoLinkedList
- //==============================================================================
-
-
- class UndoLinkedList {
-
- public:
- void operator delete(void* ptr) {DisposePtr((Ptr)ptr);}
- UndoLinkedList();
-
- ~UndoLinkedList();
-
- void Remove(UndoLink&);
-
- void AddFirst(UndoLink* link);
-
- UndoLink* RemoveFirst();
-
- UndoLink* First() const;
-
- protected:
-
- UndoLink fSentinel; // Marks the head & tail
- ODULong fSeed; // Used to detect out-of-sync iterators
-
- UndoLink* GetSentinel( )
- {return &fSentinel;}
- const UndoLink* GetSentinel( ) const
- {return &fSentinel;}
- ODBoolean IsSentinel( const UndoLink* link ) const
- {return link==this->GetSentinel();}
- ODBoolean NotSentinel( const UndoLink* link ) const
- {return link!=this->GetSentinel();}
-
- private:
- friend class UndoLinkedListIterator;
- };
-
-
- //=====================================================================================
- // UndoLinkedListIterator
- //=====================================================================================
-
- class UndoLinkedListIterator {
-
- public:
-
- UndoLinkedListIterator(UndoLinkedList* list);
-
- ~UndoLinkedListIterator();
-
- UndoLink* First();
-
- UndoLink* Next();
-
- ODBoolean IsNotComplete();
-
- private:
-
- UndoLinkedList* fList;
- UndoLink* fCurrent;
- UndoLink* fNext; // Used only when deleting while iterating
- UndoLink* fPrevious; // Used only when deleting while iterating
- UndoLink* fSentinel;
- ODULong fSeed; // Used to detect out-of-sync iterators
-
- };
-
- //==============================================================================
- // Scalar Types
- //==============================================================================
-
- typedef void* ElementType;
-
- //=====================================================================================
- // Class UndoValueLink - Definition
- //=====================================================================================
-
- class UndoValueLink : public UndoLink {
-
- public:
- UndoValueLink(ElementType value);
- ~UndoValueLink();
- ElementType GetValue() { return fValue;}
- void SetValue(ElementType v) { fValue = v;}
-
- private:
- ElementType fValue;
- };
-
- //=====================================================================================
- // Class UndoOrderedCollection
- //=====================================================================================
-
- class UndoOrderedCollection
- {
-
- public:
- void operator delete(void* ptr) {DisposePtr((Ptr)ptr);}
- UndoOrderedCollection();
- UndoOrderedCollection(ODUndoMemoryAllocation where);
- ~UndoOrderedCollection();
-
- void AddFirst(ElementType element);
- ElementType First();
- // Returns kODNULL if there is no first element.
- ElementType RemoveFirst();
- // Don't call if there are no elements. Crash will result.
- void Remove(ElementType existing);
- void RemoveAll();
-
- // Called from the destructor. Removes all elements, deleting the links
- // Does not delete the elements themselves
-
- protected:
- UndoValueLink* CreateNewLink(ElementType value) const;
- ODBoolean ElementsMatch(ElementType v1,ElementType v2) const;
- // Does a pointer comparison by default
-
- private:
- UndoLinkedList fImplementation;
- ODUndoMemoryAllocation fHeap; // if kODNULL, use default heap.
-
- friend class UndoOrderedCollectionIterator;
- friend class ListIterator;
- };
-
- //=====================================================================================
- // Class UndoOrderedCollectionIterator
- //=====================================================================================
-
- class UndoOrderedCollectionIterator {
- public:
- UndoOrderedCollectionIterator(UndoOrderedCollection* collection);
- ~UndoOrderedCollectionIterator();
- ElementType First();
- ElementType Next();
- ODBoolean IsNotComplete();
-
- private:
- UndoOrderedCollection* fCollection;
- UndoLinkedListIterator fImplementation;
- };
-
- //==============================================================================
- // UndoLink
- //==============================================================================
-
-
-
- // Many of the simple link methods are inlines; see List.h for implementations.
-
-
- //------------------------------------------------------------------------------
- // UndoLink::UndoLink
- //
- // Constructor for UndoLink
- //------------------------------------------------------------------------------
-
- UndoLink::UndoLink()
- {
- fNext = kODNULL;
- fPrevious = kODNULL;
- }
-
- //------------------------------------------------------------------------------
- // UndoLink::UndoLink
- //
- // Constructor for UndoLink
- //------------------------------------------------------------------------------
-
- UndoLink::UndoLink(UndoLink* next, UndoLink* previous)
- {
- fNext = next;
- fPrevious = previous;
- }
-
- //------------------------------------------------------------------------------
- // UndoLink::UndoLink
- //
- // Copy constructor for UndoLink
- //------------------------------------------------------------------------------
-
- UndoLink::UndoLink( const UndoLink &link )
- {
- fNext = link.fNext;
- fPrevious = link.fPrevious;
- }
-
- //------------------------------------------------------------------------------
- // UndoLink::UndoLink
- //
- // Destructor for UndoLink
- //------------------------------------------------------------------------------
-
- UndoLink::~UndoLink()
- {
- }
-
- //------------------------------------------------------------------------------
- // UndoLink::Remove
- //
- // Remove a link from its list (if any). DO NOT call this directly if there are
- // any iterators active on the list; use UndoLinkedList::Remove instead.
- //------------------------------------------------------------------------------
-
- void UndoLink::Remove( )
- {
- if( fPrevious )
- fPrevious->SetNext(fNext);
- if( fNext )
- fNext->SetPrevious(fPrevious);
- fNext = kODNULL;
- fPrevious = kODNULL;
- }
-
- //------------------------------------------------------------------------------
- // UndoLink::AddBefore
- //
- // Add a link to a list before another link. It must not already be on any list.
- // DO NOT call this directly if there are any iterators active on the list;
- // use UndoLinkedList::Remove instead.
- //------------------------------------------------------------------------------
-
- void UndoLink::AddBefore( UndoLink *link )
- {
- ASSERT(link!=kODNULL,paramErr);
- WASSERT(fNext==kODNULL);
- WASSERT(fPrevious==kODNULL);
- fNext = link;
- fPrevious = link->GetPrevious();
- fPrevious->SetNext(this);
- fNext->SetPrevious(this);
- }
-
- //------------------------------------------------------------------------------
- // UndoLink::AddAfter
- //
- // Add a link to a list after another link. It must not already be on any list.
- // DO NOT call this directly if there are any iterators active on the list;
- // use UndoLinkedList::Remove instead.
- //------------------------------------------------------------------------------
-
- void UndoLink::AddAfter( UndoLink *link )
- {
- ASSERT(link!=kODNULL,paramErr);
- WASSERT(fNext==kODNULL);
- WASSERT(fPrevious==kODNULL);
- fPrevious = link;
- fNext = link->GetNext();
- fPrevious->SetNext(this);
- fNext->SetPrevious(this);
- }
-
- //======================================================================================
- // Class UndoLinkedList
- //======================================================================================
-
- //------------------------------------------------------------------------------
- // UndoLinkedList::UndoLinkedList
- //
- // Constructor for UndoLinkedList
- //------------------------------------------------------------------------------
-
- UndoLinkedList::UndoLinkedList()
- :fSentinel(&fSentinel,&fSentinel),
- fSeed(0)
- {
- }
-
- //------------------------------------------------------------------------------
- // UndoLinkedList::~UndoLinkedList
- //
- // Destructor for UndoLinkedList
- //------------------------------------------------------------------------------
-
- UndoLinkedList::~UndoLinkedList()
- {
- // The list does NOT delete all its links!
- }
-
- //------------------------------------------------------------------------------
- // UndoLinkedList::Remove
- //
- // Description
- //------------------------------------------------------------------------------
-
- void UndoLinkedList::Remove(UndoLink& aLink)
- {
- fSeed++;
- aLink.Remove();
- }
-
- //------------------------------------------------------------------------------
- // UndoLinkedList::RemoveFirst
- //
- // Description
- //------------------------------------------------------------------------------
-
- UndoLink* UndoLinkedList::RemoveFirst()
- {
- UndoLink* old = fSentinel.GetNext();
- if (this->NotSentinel(old))
- {
- fSeed++;
- old->Remove();
- return old;
- }
- else
- {
- return kODNULL;
- }
- }
-
- //------------------------------------------------------------------------------
- // UndoLinkedList::AddFirst
- //
- // Description
- //------------------------------------------------------------------------------
-
- void UndoLinkedList::AddFirst(UndoLink* link)
- {
- link->AddAfter(this->GetSentinel());
- fSeed++;
- }
-
- //------------------------------------------------------------------------------
- // UndoLinkedList::First
- //
- // Description
- //------------------------------------------------------------------------------
-
- UndoLink* UndoLinkedList::First() const
- {
- return this->NotSentinel(fSentinel.GetNext()) ? fSentinel.GetNext() : (UndoLink*) kODNULL;
- }
-
- //======================================================================================
- // Class UndoLinkedListIterator
- //======================================================================================
-
- //------------------------------------------------------------------------------
- // UndoLinkedListIterator::UndoLinkedListIterator
- //
- // Constructor for UndoLinkedListIterator
- //------------------------------------------------------------------------------
-
- UndoLinkedListIterator::UndoLinkedListIterator(UndoLinkedList* list)
- {
- fList = list;
- fCurrent = kODNULL;
- fNext = kODNULL;
- fPrevious = kODNULL;
- fSentinel = &list->fSentinel;
- fSeed = fList->fSeed;
- }
-
- //------------------------------------------------------------------------------
- // UndoLinkedListIterator::~UndoLinkedListIterator
- //
- // Destructor for UndoLinkedListIterator
- //------------------------------------------------------------------------------
-
- UndoLinkedListIterator::~UndoLinkedListIterator()
- {
- }
-
- //------------------------------------------------------------------------------
- // UndoLinkedListIterator::First
- //
- // Description
- //------------------------------------------------------------------------------
-
- UndoLink* UndoLinkedListIterator::First()
- {
- if (fList == kODNULL)
- return kODNULL;
-
- if (fSeed != fList->fSeed)
- THROW(kODErrIteratorOutOfSync);
-
- fCurrent = fList->First();
- if (fCurrent == fSentinel)
- fCurrent = kODNULL;
- return fCurrent;
- }
-
- //------------------------------------------------------------------------------
- // UndoLinkedListIterator::Next
- //
- // Description
- //------------------------------------------------------------------------------
-
- UndoLink* UndoLinkedListIterator::Next()
- {
- if (fList == kODNULL)
- return kODNULL;
-
- if (fSeed != fList->fSeed)
- THROW(kODErrIteratorOutOfSync);
-
- if (fCurrent == kODNULL)
- {
- if ((fNext == kODNULL) && (fPrevious == kODNULL)) // Just starting out
- {
- return this->First();
- }
- else // Just deleted
- {
- fCurrent = fNext;
- fPrevious = kODNULL;
- fNext = kODNULL;
- }
- }
- else
- fCurrent = fCurrent->GetNext();
-
- if (fCurrent == fSentinel)
- fCurrent = kODNULL;
- return fCurrent;
- }
-
- //------------------------------------------------------------------------------
- // UndoLinkedListIterator::IsNotComplete
- //
- // Description
- //------------------------------------------------------------------------------
-
- ODBoolean UndoLinkedListIterator::IsNotComplete()
- {
- return (fCurrent != kODNULL);
- }
-
- //======================================================================================
- // Class UndoValueLink - Implementation
- //======================================================================================
-
- UndoValueLink::UndoValueLink(ElementType value)
- {
- fValue = value;
- }
-
- UndoValueLink::~UndoValueLink()
- {
- }
-
- //======================================================================================
- // Class UndoOrderedCollection
- //======================================================================================
-
- //------------------------------------------------------------------------------
- // UndoOrderedCollection::UndoOrderedCollection
- //------------------------------------------------------------------------------
-
- UndoOrderedCollection::UndoOrderedCollection()
- {
- fHeap = kODSystemHeap;
- }
-
- //------------------------------------------------------------------------------
- // UndoOrderedCollection::UndoOrderedCollection
- //------------------------------------------------------------------------------
-
- UndoOrderedCollection::UndoOrderedCollection(ODUndoMemoryAllocation where)
- {
- fHeap = where;
- }
-
- // UndoOrderedCollection::~UndoOrderedCollection
- //------------------------------------------------------------------------------
-
- UndoOrderedCollection::~UndoOrderedCollection()
- {
- this->RemoveAll();
- }
-
- //------------------------------------------------------------------------------
- // UndoOrderedCollection::AddFirst
- //------------------------------------------------------------------------------
-
- void UndoOrderedCollection::AddFirst(ElementType element)
- {
- UndoValueLink* newLink = this->CreateNewLink(element);
- fImplementation.AddFirst(newLink);
- }
-
- //------------------------------------------------------------------------------
- // UndoOrderedCollection::First
- //------------------------------------------------------------------------------
-
- ElementType UndoOrderedCollection::First()
- {
- UndoValueLink* firstLink = (UndoValueLink*) fImplementation.First();
- return firstLink ? firstLink->GetValue() : (ElementType)kODNULL;
- }
-
- //------------------------------------------------------------------------------
- // UndoOrderedCollection::RemoveFirst
- //------------------------------------------------------------------------------
-
- ElementType UndoOrderedCollection::RemoveFirst()
- {
- UndoValueLink* aLink = (UndoValueLink*) fImplementation.RemoveFirst();
- ElementType value = aLink ? aLink->GetValue() : kODNULL;
- delete aLink;
- return value;
- }
-
- //------------------------------------------------------------------------------
- // UndoOrderedCollection::Remove
- //------------------------------------------------------------------------------
-
- void UndoOrderedCollection::Remove(ElementType existing)
- {
- UndoLinkedListIterator iter(&fImplementation);
- UndoValueLink* aLink = (UndoValueLink*) iter.First();
- while (aLink != kODNULL)
- {
- ElementType v = ((UndoValueLink*) aLink)->GetValue();
-
- if (this->ElementsMatch(v,existing))
- {
- fImplementation.Remove(*aLink);
- delete aLink;
- aLink = kODNULL;
- }
- else
- aLink = (UndoValueLink*) iter.Next();
- }
- }
-
- //------------------------------------------------------------------------------
- // UndoOrderedCollection::RemoveAll
- //------------------------------------------------------------------------------
-
- void UndoOrderedCollection::RemoveAll()
- {
- UndoLink* link = fImplementation.RemoveFirst();
- while (link != kODNULL)
- {
- delete link;
- link = fImplementation.RemoveFirst();
- }
- }
-
- //------------------------------------------------------------------------------
- // UndoOrderedCollection::CreateNewLink
- //------------------------------------------------------------------------------
-
- UndoValueLink* UndoOrderedCollection::CreateNewLink(ElementType value) const
- {
- return new (fHeap) UndoValueLink(value);
- }
-
- //------------------------------------------------------------------------------
- // UndoOrderedCollection::ElementsMatch
- //------------------------------------------------------------------------------
-
- ODBoolean UndoOrderedCollection::ElementsMatch(ElementType v1,ElementType v2) const
- {
- return (v1 == v2);
- }
-
- //======================================================================================
- // UndoOrderedCollectionIterator
- //======================================================================================
-
- //------------------------------------------------------------------------------
- // UndoOrderedCollectionIterator::UndoOrderedCollectionIterator
- //------------------------------------------------------------------------------
-
- UndoOrderedCollectionIterator::UndoOrderedCollectionIterator(UndoOrderedCollection* collection)
- : fImplementation(collection ? &(collection->fImplementation) : (UndoLinkedList*)kODNULL)
- {
- fCollection = collection;
- }
-
- //------------------------------------------------------------------------------
- // UndoOrderedCollectionIterator::~UndoOrderedCollectionIterator
- //------------------------------------------------------------------------------
-
- UndoOrderedCollectionIterator::~UndoOrderedCollectionIterator()
- {
- }
-
- //------------------------------------------------------------------------------
- // UndoOrderedCollectionIterator::First
- //------------------------------------------------------------------------------
-
- ElementType UndoOrderedCollectionIterator::First()
- {
- UndoValueLink* link = (UndoValueLink*) fImplementation.First();
-
- return link ? link->GetValue() : (ElementType)kODNULL;
- }
-
- //------------------------------------------------------------------------------
- // UndoOrderedCollectionIterator::Next
- //------------------------------------------------------------------------------
-
- ElementType UndoOrderedCollectionIterator::Next()
- {
- UndoValueLink* link = (UndoValueLink*) fImplementation.Next();
-
- return link ? link->GetValue() : (ElementType)kODNULL;
- }
-
- //------------------------------------------------------------------------------
- // UndoOrderedCollectionIterator::IsNotComplete
- //------------------------------------------------------------------------------
-
- ODBoolean UndoOrderedCollectionIterator::IsNotComplete()
- {
- return fImplementation.IsNotComplete();
- }
-
-
-
- /////////////// END TEMP HACK
-
-
-
- //==============================================================================
- // Constants
- //==============================================================================
-
- const OSType kUndoNotifyID = 'undo';
- const OSType kRedoNotifyID = 'redo';
- const OSType kDisposeActionNotifyID = 'del ';
-
- const AEKeyword kDataPtrKeyword = 'data';
- const AEKeyword kPartPtrKeyword = 'part';
- const AEKeyword kDoneStateKeyword = 'done';
-
- // A number of functions can share code. They pass along this enum to know
- // which course of action to take.
- enum ODUndoRedoType
- {
- kUndo,
- kRedo,
- kDispose
- };
-
- //==============================================================================
- // Classes used in this file
- //==============================================================================
-
- class UndoAction;
- class SystemUndo;
-
- //==============================================================================
- // Function Prototypes
- //==============================================================================
-
- static OSErr NotifyUndoOrRedoOrDispose(UndoAction* action,
- ODUndoRedoType which);
- static OSErr NotifyUndo(UndoAction* action);
- static OSErr NotifyRedo(UndoAction* action);
- static OSErr NotifyDispose(UndoAction* action);
- static SystemUndo *GetSystemUndo();
- static ODBoolean SetSystemUndo(SystemUndo *systemUndo);
-
- //==============================================================================
- // Functions
- //==============================================================================
-
- // • Using ASLM we registered the system undo object with ASLM using the
- // arbitration mechanism provided by ASLM. To eliminate our dependency on ASLM
- // we are storing the system undo object in a global which is accessed by the
- // following two functions. This is NOT a thread safe method for accessing the
- // system undo!
-
- //------------------------------------------------------------------------------
- // GetSystemUndo
- //------------------------------------------------------------------------------
-
- #pragma lib_export on
- extern SystemUndo* gSystemUndo;
- #pragma lib_export off
-
- static SystemUndo *GetSystemUndo()
- {
- return gSystemUndo;
- }
-
- //------------------------------------------------------------------------------
- // SetSystemUndo
- //------------------------------------------------------------------------------
-
- static ODBoolean SetSystemUndo(SystemUndo *systemUndo)
- {
- gSystemUndo = systemUndo;
- return kODTrue;
- }
-
- //#pragma lib_export off
-
- //==============================================================================
- // Local Classes
- //==============================================================================
-
- //------------------------------------------------------------------------------
-
- class UndoAction
- {
- public:
- void operator delete(void* ptr) {DisposePtr((Ptr)ptr);}
- UndoAction(ODPart* whichPart, ODActionData* actionData,
- ODActionType actionType, ODName* undoActionLabel,
- ODName* redoActionLabel);
- ~UndoAction();
-
- ODPart* fPart;
- ProcessSerialNumber fProcessNum;
- ODActionData* fActionData;
- ODActionType fActionType;
- ODName* fUndoActionLabel;
- ODName* fRedoActionLabel;
- ODBoolean fMark;
- ODDoneState fDoneState;
- };
-
- //------------------------------------------------------------------------------
- // UndoAction::UndoAction
- //
- // This constructor may throw an error, but it's OK because there is nothing
- // to deallocate in the destructor.
- //------------------------------------------------------------------------------
-
- UndoAction::UndoAction(ODPart* whichPart,
- ODActionData* actionData,
- ODActionType actionType,
- ODName* undoActionLabel,
- ODName* redoActionLabel)
- {
- fPart = whichPart;
- THROW_IF_ERROR(GetCurrentProcess(&fProcessNum));
- fActionData = actionData;
- fActionType = actionType;
- fUndoActionLabel = undoActionLabel;
- fRedoActionLabel = redoActionLabel;
- fMark = kODFalse;
- fDoneState = kODDone;
- }
-
- //------------------------------------------------------------------------------
- // UndoAction::~UndoAction
- //
- // Notify owning part owning fActionData to dipose of any associated memory.
- //------------------------------------------------------------------------------
-
- UndoAction::~UndoAction()
- {
- NotifyDispose(this);
-
- DisposeIText(fUndoActionLabel);
- DisposeIText(fRedoActionLabel);
- DisposeByteArray(fActionData);
- }
-
- //------------------------------------------------------------------------------
-
- class SystemUndo
- {
- public:
- void operator delete(void* ptr) {DisposePtr((Ptr)ptr);}
- SystemUndo();
- ~SystemUndo();
- void Initialize();
-
- ODSize Purge(ODSize size);
- ODBoolean CheckActionOK(UndoAction* action);
- void AddActionToHistory(ODPart* whichPart,
- ODActionData* actionData,
- ODActionType actionType,
- ODName* undoActionLabel,
- ODName* redoActionLabel);
- void Undo();
- void Redo();
- void MarkActionHistory();
- void ClearActionHistory(ODRespectMarksChoices respectMarks);
- void ClearRedoHistory();
- ODBoolean PeekUndoHistory(ODPart** part,
- ODActionData* actionData,
- ODActionType* actionType,
- ODName* actionLabel);
- ODBoolean PeekRedoHistory(ODPart** part,
- ODActionData* actionData,
- ODActionType* actionType,
- ODName* actionLabel);
- void RemoveEntriesForThisProcess();
- void AddClient(ODUndo* docUndoObject);
- void RemoveClient(ODUndo* docUndoObject);
- ODULong GetNumClients();
- void AbortCurrentTransaction();
- private:
- void TransactionUndo(UndoAction* firstAction);
- void TransactionRedo(UndoAction* firstAction);
- void MarkActionOrSelf(UndoAction* action, ODBoolean* mark);
- void ClearActionsToMark(UndoOrderedCollection* stack);
- void ClearStack(UndoOrderedCollection* stack);
- ODBoolean PeekHistory(ODPart** part,
- ODActionData* actionData,
- ODActionType* actionType,
- ODName* actionLabel,
- ODUndoRedoType which);
- void MoveUndoToRedo();
- void MoveRedoToUndo();
-
- UndoOrderedCollection* fUndoStack;
- UndoOrderedCollection* fRedoStack;
- ODULong fInTransaction;
- ODBoolean fCurrentlyUndoingOrRedoing;
- ODULong fNumUsers;
- };
-
- //------------------------------------------------------------------------------
- // SystemUndo::SystemUndo
- //------------------------------------------------------------------------------
-
- SystemUndo::SystemUndo()
- {
- fUndoStack = kODNULL;
- fRedoStack = kODNULL;
- fInTransaction = 0;
- fCurrentlyUndoingOrRedoing = kODFalse;
- fNumUsers = 0;
- }
-
- //------------------------------------------------------------------------------
- // SystemUndo::Initialize
- //------------------------------------------------------------------------------
-
- void SystemUndo::Initialize ()
- {
- ODUndoMemoryAllocation heap = kODSystemHeap;
-
- fUndoStack = new (heap) UndoOrderedCollection(heap);
- fRedoStack = new (heap) UndoOrderedCollection(heap);
-
- }
-
- //------------------------------------------------------------------------------
- // SystemUndo::~SystemUndo
- //------------------------------------------------------------------------------
-
- SystemUndo::~SystemUndo()
- {
- // WASSERTM(0, "System Undo object being destroyed!");
- delete fUndoStack;
- delete fRedoStack;
- }
-
- //------------------------------------------------------------------------------
- // SystemUndo::Purge
- //------------------------------------------------------------------------------
-
- ODSize SystemUndo::Purge(ODSize size)
- {
- ODUnused(size);
- return 0;
- }
-
- //------------------------------------------------------------------------------
- // SystemUndo::CheckActionOK
- //------------------------------------------------------------------------------
-
- ODBoolean SystemUndo::CheckActionOK(UndoAction* action)
- {
- if (action && !(action->fMark))
- return kODTrue;
- return kODFalse;
- }
-
- //------------------------------------------------------------------------------
- // SystemUndo::AddClient
- //------------------------------------------------------------------------------
-
- void SystemUndo::AddClient(ODUndo* docUndoObject)
- {
- ODUnused(docUndoObject);
- ++fNumUsers;
- }
-
- //------------------------------------------------------------------------------
- // SystemUndo::RemoveClient
- //------------------------------------------------------------------------------
-
- void SystemUndo::RemoveClient(ODUndo* docUndoObject)
- {
- ODUnused(docUndoObject);
- --fNumUsers;
- }
-
- //------------------------------------------------------------------------------
- // SystemUndo::GetNumClients
- //------------------------------------------------------------------------------
-
- ODULong SystemUndo::GetNumClients()
- {
- return fNumUsers;
- }
-
- //------------------------------------------------------------------------------
- // SystemUndo::AddActionToHistory
- //------------------------------------------------------------------------------
-
- void SystemUndo::AddActionToHistory(ODPart* whichPart,
- ODActionData* actionData,
- ODActionType actionType,
- ODName* undoActionLabel,
- ODName* redoActionLabel)
- {
- if (fCurrentlyUndoingOrRedoing)
- THROW(kODErrCannotAddAction);
-
- // if (fInTransaction && actionType == kODBeginAction)
- // THROW(kODErrCannotAddAction);
-
- if (actionType == kODBeginAction)
- ++fInTransaction;
- if (actionType == kODEndAction)
- --fInTransaction;
-
- // NOT DOING THESE ALLOCATIONS IN THE SYSTEM HEAP!
- ODIText* undoName = CopyIText(undoActionLabel);
- ODIText* redoName = CopyIText(redoActionLabel);
-
- ODActionData* copiedData = (ODActionData*)ODNewPtr(sizeof(ODActionData));
- copiedData->_buffer = (octet*)ODNewPtr(actionData->_length);
- ODBlockMove(actionData->_buffer, copiedData->_buffer, actionData->_length);
- copiedData->_length = actionData->_length;
- copiedData->_maximum = actionData->_length;
-
- UndoAction* action =
- new (kODSystemHeap) UndoAction(whichPart, copiedData,
- actionType, undoName,
- redoName);
- fUndoStack->AddFirst(action);
- this->ClearStack(fRedoStack);
- }
-
- //------------------------------------------------------------------------------
- // SystemUndo::MoveUndoToRedo
- //
- // Utility to move item from top of one stack to the top of another.
- //------------------------------------------------------------------------------
-
- void SystemUndo::MoveUndoToRedo()
- {
- ElementType item = fUndoStack->RemoveFirst();
- ((UndoAction*)item)->fDoneState = kODUndone;
- fRedoStack->AddFirst(item);
- }
-
- //------------------------------------------------------------------------------
- // SystemUndo::MoveRedoToUndo
- //
- // Utility to move item from top of one stack to the top of another.
- //------------------------------------------------------------------------------
-
- void SystemUndo::MoveRedoToUndo()
- {
- ElementType item = fRedoStack->RemoveFirst();
- ((UndoAction*)item)->fDoneState = kODRedone;
- fUndoStack->AddFirst(item);
- }
-
- //------------------------------------------------------------------------------
- // SystemUndo::Undo
- //
- // If there's an error while undoing anything, just clear the stacks and get
- // out.
- //------------------------------------------------------------------------------
-
- void SystemUndo::Undo()
- {
- UndoAction* action = (UndoAction*)fUndoStack->First();
- if (!this->CheckActionOK(action))
- THROW(kODErrEmptyStack);
-
- fCurrentlyUndoingOrRedoing = kODTrue;
-
- TRY
- if (action->fActionType == kODEndAction) // End is at top for an Undo
- this->TransactionUndo(action);
- else
- {
- THROW_IF_ERROR(NotifyUndo(action));
- this->MoveUndoToRedo();
- }
- CATCH_ALL
- this->ClearActionHistory(kODDontRespectMarks);
- fCurrentlyUndoingOrRedoing = kODFalse;
- RERAISE;
- ENDTRY
- fCurrentlyUndoingOrRedoing = kODFalse;
- }
-
- //------------------------------------------------------------------------------
- // SystemUndo::TransactionUndo
- //------------------------------------------------------------------------------
-
- void SystemUndo::TransactionUndo(UndoAction* firstAction)
- {
- UndoAction* action;
- ODULong nestedTransactionCounter = 1;
-
- THROW_IF_ERROR(NotifyUndo(firstAction));
- this->MoveUndoToRedo();
-
- do
- {
- action = (UndoAction*)fUndoStack->First();
- if (action == (UndoAction*)kODNULL)
- THROW(kODErrNoBeginAction);
- THROW_IF_ERROR(NotifyUndo(action));
- this->MoveUndoToRedo();
- if (action->fActionType == kODBeginAction)
- --nestedTransactionCounter;
- else if (action->fActionType == kODEndAction)
- ++nestedTransactionCounter;
- }
- while (nestedTransactionCounter);
- }
-
- //------------------------------------------------------------------------------
- // SystemUndo::Redo
- //------------------------------------------------------------------------------
-
- void SystemUndo::Redo()
- {
- UndoAction* action = (UndoAction*)fRedoStack->First();
- if (!this->CheckActionOK(action))
- THROW(kODErrEmptyStack);
-
- fCurrentlyUndoingOrRedoing = kODTrue;
-
- TRY
- if (action->fActionType == kODBeginAction)//Start is at top for an Redo
- this->TransactionRedo(action);
- else
- {
- THROW_IF_ERROR(NotifyRedo(action));
- this->MoveRedoToUndo();
- }
- CATCH_ALL
- this->ClearActionHistory(kODDontRespectMarks);
- fCurrentlyUndoingOrRedoing = kODFalse;
- RERAISE;
- ENDTRY
- fCurrentlyUndoingOrRedoing = kODFalse;
- }
-
- //------------------------------------------------------------------------------
- // SystemUndo::TransactionRedo
- //------------------------------------------------------------------------------
-
- void SystemUndo::TransactionRedo(UndoAction* firstAction)
- {
- UndoAction* action;
- ODULong nestedTransactionCounter = 1;
-
- THROW_IF_ERROR(NotifyRedo(firstAction));
- this->MoveRedoToUndo();
-
- do
- {
- action = (UndoAction*)fRedoStack->First();
- // if (action == (UndoAction*)kODNULL)
- // THROW(kODErrNoBeginAction);
- THROW_IF_ERROR(NotifyRedo(action));
- this->MoveRedoToUndo();
- if (action->fActionType == kODBeginAction)
- ++nestedTransactionCounter;
- else if (action->fActionType == kODEndAction)
- --nestedTransactionCounter;
- }
- while (nestedTransactionCounter);
- }
-
- //------------------------------------------------------------------------------
- // SystemUndo::MarkActionHistory
- //------------------------------------------------------------------------------
-
- void SystemUndo::MarkActionHistory()
- {
- UndoAction* action;
-
- action = (UndoAction*)fUndoStack->First();
- if (action)
- action->fMark = kODTrue;
- action = (UndoAction*)fRedoStack->First();
- if (action)
- action->fMark = kODTrue;
- }
-
- //------------------------------------------------------------------------------
- // SystemUndo::ClearStack
- //------------------------------------------------------------------------------
-
- void SystemUndo::ClearStack(UndoOrderedCollection* stack)
- {
- UndoOrderedCollectionIterator iter(stack);
- UndoAction* action;
-
- for (action = (UndoAction*)iter.First();
- iter.IsNotComplete();
- action = (UndoAction*)iter.Next())
- {
- delete action;
- }
-
- stack->RemoveAll();
- }
-
- //------------------------------------------------------------------------------
- // SystemUndo::ClearActionsToMark
- //
- // To make more efficient, should just start removing items from the front of
- // the list til I hit the mark.
- //------------------------------------------------------------------------------
-
- void SystemUndo::ClearActionsToMark(UndoOrderedCollection* stack)
- {
- UndoOrderedCollectionIterator collectionIter(stack);
- UndoAction* action;
- UndoOrderedCollection elementsToDelete;
-
- // ADD ELEMENTS TO REMOVE TO A LIST
- for (action = (UndoAction*)collectionIter.First();
- collectionIter.IsNotComplete();
- action = (UndoAction*)collectionIter.Next())
- {
- if (action->fMark != kODFalse)
- {
- action->fMark = kODFalse;
- break;
- }
- else
- elementsToDelete.AddFirst(action);
- }
-
- // REMOVE ELEMENTS
- UndoOrderedCollectionIterator deleteIter(&elementsToDelete);
- for (action = (UndoAction*)deleteIter.First();
- deleteIter.IsNotComplete();
- action = (UndoAction*)deleteIter.Next())
- {
- stack->Remove(action);
- delete action;
- }
- }
-
- //------------------------------------------------------------------------------
- // SystemUndo::ClearActionHistory
- //------------------------------------------------------------------------------
-
- void SystemUndo::ClearActionHistory(ODRespectMarksChoices respectMarks)
- {
- if (respectMarks == kODRespectMarks)
- {
- this->ClearActionsToMark(fUndoStack);
- this->ClearActionsToMark(fRedoStack);
- }
- else
- {
- this->ClearStack(fUndoStack);
- this->ClearStack(fRedoStack);
- }
- }
-
- //------------------------------------------------------------------------------
- // SystemUndo::ClearRedoHistory
- //------------------------------------------------------------------------------
-
- void SystemUndo::ClearRedoHistory()
- {
- this->ClearActionsToMark(fRedoStack);
- }
-
- //------------------------------------------------------------------------------
- // SystemUndo::AbortCurrentTransaction
- //------------------------------------------------------------------------------
-
- void SystemUndo::AbortCurrentTransaction()
- {
- ODULong nestingLevel = 0;
- ODActionType actionType;
-
- if (fCurrentlyUndoingOrRedoing)
- return;
- if (!fInTransaction)
- return;
-
- UndoAction* action = (UndoAction*)fUndoStack->First();
-
- do
- {
- if (action->fActionType == kODEndAction)
- ++nestingLevel;
- fUndoStack->RemoveFirst();
- actionType = action->fActionType;
- delete action;
- if (actionType == kODBeginAction && nestingLevel == 0)
- break;
- action = (UndoAction*)fUndoStack->First();//should never be NULL, right?
- }
- while (kODTrue);
- }
-
- //------------------------------------------------------------------------------
- // SystemUndo::PeekUndoHistory
- //------------------------------------------------------------------------------
-
- ODBoolean SystemUndo::PeekUndoHistory(ODPart** part,
- ODActionData* actionData,
- ODActionType* actionType,
- ODName* actionLabel)
- {
- return PeekHistory(part, actionData, actionType, actionLabel, kUndo);
- }
-
- //------------------------------------------------------------------------------
- // SystemUndo::PeekRedoHistory
- //------------------------------------------------------------------------------
-
- ODBoolean SystemUndo::PeekRedoHistory(ODPart** part,
- ODActionData* actionData,
- ODActionType* actionType,
- ODName* actionLabel)
- {
- return PeekHistory(part, actionData, actionType, actionLabel, kRedo);
- }
-
- //------------------------------------------------------------------------------
- // SystemUndo::PeekHistory
- //------------------------------------------------------------------------------
-
- ODBoolean SystemUndo::PeekHistory(ODPart** part,
- ODActionData* actionData,
- ODActionType* actionType,
- ODName* actionLabel,
- ODUndoRedoType which)
- {
- UndoOrderedCollection* stack;
- ODIText* iText;
-
- if (which == kUndo)
- stack = fUndoStack;
- else if (which == kRedo)
- stack = fRedoStack;
-
- UndoAction* action = (UndoAction*)stack->First();
-
- if (!this->CheckActionOK(action))
- return kODFalse;
- else
- {
- if (action->fMark != kODFalse)
- return kODFalse;
- else
- {
- *part = action->fPart;
- *actionType = action->fActionType;
-
- *actionData = CopyByteArrayStruct(action->fActionData);
-
- if (which == kUndo)
- iText = action->fUndoActionLabel;
- else if (which == kRedo)
- iText = action->fRedoActionLabel;
-
- *actionLabel = CopyITextStruct(iText);
-
- return kODTrue;
- }
- }
- }
-
- //------------------------------------------------------------------------------
- // NotifyUndoOrRedoOrDispose
- //
- // Notify part to Undo or Redo or Dispose its data.
- // Could fine-tune to only pack parameters needed according to "which"
- // parameter
- //------------------------------------------------------------------------------
-
- static OSErr NotifyUndoOrRedoOrDispose(UndoAction* action,
- ODUndoRedoType which)
- {
- AEAddressDesc address;
- AppleEvent message;
- AppleEvent reply;
- OSErr error = noErr;
- ProcessSerialNumber psn;
- Boolean isSameProcess;
- DescType eventID;
- // ProcessInfoRec processRec;
-
- TRY
- #if 0
- // MAKE SURE PROCESS IS STILL VALID. USE SIDE EFFECT OF ERROR RETURN
- // FROM GetProcessInformation.
- processRec.processInfoLength = sizeof(ProcessInfoRec);
- processRec.processName = kODNULL;
- processRec.processAppSpec = kODNULL;
- THROW_IF_ERROR(GetProcessInformation(&action->fProcessNum, &processRec));
- #endif /* 0 */
- // SOME CODE TO HANDLE THE SEND TO SELF CASE WELL. IF WE HAVE A STANDARD
- // IDLE PROC TO USE, WE PROBABLY DON'T NEED THIS. (NP-WHAT DID I MEAN
- // HERE?)
- THROW_IF_ERROR(GetCurrentProcess(&psn));
- THROW_IF_ERROR(SameProcess(&action->fProcessNum, &psn,
- &isSameProcess));
- if (isSameProcess)
- {
- psn.lowLongOfPSN = kCurrentProcess;
- psn.highLongOfPSN = 0;
- }
- else
- psn = action->fProcessNum;
- #if 0
- {
- // MAKE SURE PROCESS IS STILL ALIVE.
- ODBoolean processStillExists = kODFalse;
-
- while (kODTrue)
- {
- if (GetNextProcess(&psn) != noErr)
- break;
- THROW_IF_ERROR(SameProcess(&action->fProcessNum, &psn,
- &isSameProcess));
- if (isSameProcess)
- {
- processStillExists = kODTrue;
- break;
- }
- }
-
- if (!processStillExists)
- THROW(procNotFound);
- }
- #endif /* 0 */
- THROW_IF_ERROR(AECreateDesc(typeProcessSerialNumber,
- (Ptr)&psn, sizeof(psn), &address));
-
- if (which == kUndo)
- eventID = kUndoNotifyID;
- else if (which == kRedo)
- eventID = kRedoNotifyID;
- else if (which == kDispose)
- eventID = kDisposeActionNotifyID;
-
- THROW_IF_ERROR(AECreateAppleEvent(kODShellSignature, eventID,
- &address, kAutoGenerateReturnID, kAnyTransactionID,
- &message));
- TempAEDesc tempMessage(&message); // DMc make sure it is disposed
-
- THROW_IF_ERROR(AEPutParamPtr(&message, kDataPtrKeyword, typeChar,
- action->fActionData->_buffer,
- action->fActionData->_length));
-
- THROW_IF_ERROR(AEPutParamPtr(&message, kPartPtrKeyword, typeInteger,
- (Ptr)&action->fPart,
- sizeof(action->fPart)));
-
- THROW_IF_ERROR(AEPutParamPtr(&message, kDoneStateKeyword, typeInteger,
- (Ptr)&action->fDoneState,
- sizeof(action->fDoneState)));
-
- THROW_IF_ERROR(AESend(&message, &reply,
- kAEWaitReply + kAECanInteract + kAECanSwitchLayer
- + kAEDontRecord,
- kAENormalPriority,
- // NP: TEMP FIX: CHANGE TIMEOUT TO 5 SECONDS IF
- // SENDING A DISPOSE. *MAY* CAUSE MEMORY LEAKS,
- // OR, IN THE WORSE CASE, THAT SOME NOTIFICATIONS
- // WILL BE SENT AND OTHERS NOT. THIS MAY CONFUSE
- // A PART.
- (which == kDispose ? 5 * 60 : kAEDefaultTimeout),
- (AEIdleUPP)kODNULL,
- // kAEDefaultTimeout, (AEIdleUPP)kODNULL,
- (AEFilterUPP)kODNULL));
- AEDisposeDesc(&reply); // DMc
- CATCH_ALL
- error = ErrorCode();
- ENDTRY
-
- return error;
- }
-
- //------------------------------------------------------------------------------
- // NotifyUndo
- //
- // Call ODPart::Undo.
- //------------------------------------------------------------------------------
-
- static OSErr NotifyUndo(UndoAction* action)
- {
- return NotifyUndoOrRedoOrDispose(action, kUndo);
- }
-
- //------------------------------------------------------------------------------
- // NotifyRedo
- //
- // Call ODPart::Redo.
- //------------------------------------------------------------------------------
-
- static OSErr NotifyRedo(UndoAction* action)
- {
- return NotifyUndoOrRedoOrDispose(action, kRedo);
- }
-
- //------------------------------------------------------------------------------
- // NotifyDispose
- //
- // Call ODPart::DiposeActionState.
- //------------------------------------------------------------------------------
-
- static OSErr NotifyDispose(UndoAction* action)
- {
- return NotifyUndoOrRedoOrDispose(action, kDispose);
- }
-
- //==============================================================================
- // ODUndo
- //==============================================================================
-
- //------------------------------------------------------------------------------
- // HandleUndoOrRedoOrDisposeNotify
- //
- // Could fine-tune to only unpack parameters needed according to "which"
- // parameter
- //------------------------------------------------------------------------------
-
- static OSErr HandleUndoOrRedoOrDisposeNotify(AppleEvent* message,
- AppleEvent* reply,
- long refCon,
- ODUndoRedoType which)
- {
- ODUnused(reply);
- ODUnused(refCon);
-
- OSErr error = noErr;
- DescType gotType;
- ODActionData* data;
- ODPart* part;
- ODDoneState doneState;
- Size actualSize;
- Size maximumDataSize;
- Size maximumPartSize = sizeof(part);
- Size maximumDoneStateSize = sizeof(doneState);
-
- TRY
- gotType = typeChar;
- THROW_IF_ERROR(AESizeOfParam(message, kDataPtrKeyword, &gotType,
- &actualSize));
- if (gotType != typeChar)
- THROW(errAECorruptData);
- maximumDataSize = actualSize;
- data = CreateEmptyByteArray(actualSize);
- THROW_IF_ERROR(AEGetParamPtr(message, kDataPtrKeyword, typeChar,
- &gotType, data->_buffer, maximumDataSize,
- &actualSize));
- if (actualSize != maximumDataSize)
- THROW(errAECorruptData);
-
- THROW_IF_ERROR(AEGetParamPtr(message, kPartPtrKeyword, typeInteger,
- &gotType, (Ptr)&part, maximumPartSize,
- &actualSize));
- if (gotType != typeInteger || actualSize != maximumPartSize)
- THROW(errAECorruptData);
-
- THROW_IF_ERROR(AEGetParamPtr(message, kDoneStateKeyword, typeInteger,
- &gotType, (Ptr)&doneState,
- maximumDoneStateSize,
- &actualSize));
- if (gotType != typeInteger || actualSize != maximumDoneStateSize)
- THROW(errAECorruptData);
-
- Environment* ev = somGetGlobalEnvironment();
- if (which == kUndo)
- {
- part->UndoAction(ev, data);
- error = ODGetSOMException(ev);
- }
- else if (which == kRedo)
- {
- part->RedoAction(ev, data);
- error = ODGetSOMException(ev);
- }
- else if (which == kDispose)
- {
- part->DisposeActionState(ev, data, doneState);
- error = ODGetSOMException(ev);
- }
-
- DisposeByteArray(data);
-
- CATCH_ALL
- error = ErrorCode();
- ENDTRY
-
- return error;
- }
-
- //------------------------------------------------------------------------------
- // HandleUndoNotify
- //------------------------------------------------------------------------------
-
- static pascal OSErr HandleUndoNotify(AppleEvent* message, AppleEvent* reply,
- long refCon)
- {
- return HandleUndoOrRedoOrDisposeNotify(message, reply, refCon, kUndo);
- }
-
- //------------------------------------------------------------------------------
- // HandleRedoNotify
- //------------------------------------------------------------------------------
-
- static pascal OSErr HandleRedoNotify(AppleEvent* message, AppleEvent* reply,
- long refCon)
- {
- return HandleUndoOrRedoOrDisposeNotify(message, reply, refCon, kRedo);
- }
-
- //------------------------------------------------------------------------------
- // HandleDisposeNotify
- //------------------------------------------------------------------------------
-
- static pascal OSErr HandleDisposeNotify(AppleEvent* message, AppleEvent* reply,
- long refCon)
- {
- return HandleUndoOrRedoOrDisposeNotify(message, reply, refCon, kDispose);
- }
-
- //------------------------------------------------------------------------------
- // ODUndo::InitUndo
- //------------------------------------------------------------------------------
-
- SOM_Scope void SOMLINK ODUndoInitUndo(ODUndo *somSelf, Environment *ev)
- {
- ODUndoData *somThis = ODUndoGetData(somSelf);
- ODUndoMethodDebug("ODUndo","ODUndoInitUndo");
-
- /* Moved from somInit. SOM itself sets fields to zero
- _fSystemUndo = kODNULL;
- */
-
- TRY
- somSelf->InitObject(ev);
-
- _fSystemUndo = GetSystemUndo();
- if (!_fSystemUndo)
- {
- _fSystemUndo = new (kODSystemHeap) SystemUndo();
- if (_fSystemUndo)
- {
- _fSystemUndo->Initialize();
- SetSystemUndo(_fSystemUndo);
- }
- }
- THROW_IF_ERROR(AEInstallEventHandler(kODShellSignature,
- kUndoNotifyID,
- NewAEEventHandlerProc(HandleUndoNotify),
- (long)somSelf, !kIsSysHandler));
- THROW_IF_ERROR(AEInstallEventHandler(kODShellSignature,
- kRedoNotifyID,
- NewAEEventHandlerProc(HandleRedoNotify),
- (long)somSelf, !kIsSysHandler));
- THROW_IF_ERROR(AEInstallEventHandler(kODShellSignature,
- kDisposeActionNotifyID,
- NewAEEventHandlerProc(HandleDisposeNotify),
- (long)somSelf, !kIsSysHandler));
- _fSystemUndo->AddClient(somSelf);
- CATCH_ALL
- ODDeleteObject(_fSystemUndo);
- ODSetSOMException(ev, ErrorCode());
- ENDTRY
- }
-
- //------------------------------------------------------------------------------
- // ODUndo::~ODUndo
- //------------------------------------------------------------------------------
-
- SOM_Scope void SOMLINK ODUndosomUninit(ODUndo *somSelf)
- {
- ODUndoData *somThis = ODUndoGetData(somSelf);
- ODUndoMethodDebug("ODUndo","ODUndosomUninit");
-
- if (_fSystemUndo)
- {
- _fSystemUndo->RemoveClient(somSelf);
-
- if (_fSystemUndo->GetNumClients() == 0) // reclaim space.
- {
- // WARN("Deleting system undo object.");
- ODDeleteObject(_fSystemUndo);
- SetSystemUndo(kODNULL);
- }
- }
- ODUndo_parents_somUninit(somSelf);
- }
- #if 0
- //------------------------------------------------------------------------------
- // ODUndo::Purge
- //------------------------------------------------------------------------------
-
- SOM_Scope ODSize SOMLINK ODUndoPurge(ODUndo *somSelf, Environment *ev,
- ODSize size)
- {
- ODUndoData *somThis = ODUndoGetData(somSelf);
- ODUndoMethodDebug("ODUndo","ODUndoPurge");
-
- ODSize purged = 0;
- ODVolatile(purged);
-
- SOM_TRY
- if (_fSystemUndo) {
- purged = _fSystemUndo->Purge(size);
- }
- else
- purged = 0;
-
- purged += parent_Purge(somSelf,ev,size);
- SOM_CATCH_ALL
- WARN("Error %ld trying to purge in ODUndoPurge",ErrorCode());
- SetErrorCode(kODNoError); // dh - Eat the exception; Purge should not
- // propagate it because clients function
- // fine whether memory was purged or not.
- SOM_ENDTRY
-
- return purged;
- }
- #endif /* 0 */
- //------------------------------------------------------------------------------
- // ODUndo::AddActionToHistory
- //------------------------------------------------------------------------------
-
- SOM_Scope void SOMLINK ODUndoAddActionToHistory(ODUndo *somSelf, Environment *ev,
- ODPart* whichPart,
- ODActionData* actionData,
- ODActionType actionType,
- ODName* undoActionLabel,
- ODName* redoActionLabel)
- {
- ODUndoData *somThis = ODUndoGetData(somSelf);
- ODUndoMethodDebug("ODUndo","ODUndoAddActionToHistory");
-
- SOM_CATCH
- return;
-
- if (_fSystemUndo)
- _fSystemUndo->AddActionToHistory(whichPart, actionData, actionType,
- undoActionLabel, redoActionLabel);
- else
- THROW(kODErrOutOfMemory);
- }
-
- //------------------------------------------------------------------------------
- // ODUndo::Undo
- //------------------------------------------------------------------------------
-
- SOM_Scope void SOMLINK ODUndoUndo(ODUndo *somSelf, Environment *ev)
- {
- ODUndoData *somThis = ODUndoGetData(somSelf);
- ODUndoMethodDebug("ODUndo","ODUndoUndo");
-
- SOM_CATCH
- return;
-
- if (_fSystemUndo)
- _fSystemUndo->Undo();
- else
- THROW(kODErrEmptyStack);
- }
-
- //------------------------------------------------------------------------------
- // ODUndo::Redo
- //------------------------------------------------------------------------------
-
- SOM_Scope void SOMLINK ODUndoRedo(ODUndo *somSelf, Environment *ev)
- {
- ODUndoData *somThis = ODUndoGetData(somSelf);
- ODUndoMethodDebug("ODUndo","ODUndoRedo");
-
- SOM_CATCH
- return;
-
- if (_fSystemUndo)
- _fSystemUndo->Redo();
- else
- THROW(kODErrEmptyStack);
- }
-
- //------------------------------------------------------------------------------
- // ODUndo::MarkActionHistory
- //------------------------------------------------------------------------------
-
- SOM_Scope void SOMLINK ODUndoMarkActionHistory(ODUndo *somSelf, Environment *ev)
- {
- ODUndoData *somThis = ODUndoGetData(somSelf);
- ODUndoMethodDebug("ODUndo","ODUndoMarkActionHistory");
-
- SOM_CATCH
- return;
-
- if (_fSystemUndo)
- _fSystemUndo->MarkActionHistory();
- else
- THROW(kODErrCannotMarkAction);
- }
-
- //------------------------------------------------------------------------------
- // ODUndo::ClearActionHistory
- //------------------------------------------------------------------------------
-
- SOM_Scope void SOMLINK ODUndoClearActionHistory(ODUndo *somSelf, Environment *ev,
- ODRespectMarksChoices respectMarks)
- {
- ODUndoMethodDebug("ODUndo","ODUndoClearActionHistory");
- ODUndoData *somThis = ODUndoGetData(somSelf);
-
- SOM_CATCH
- return;
-
- if (_fSystemUndo)
- _fSystemUndo->ClearActionHistory(respectMarks);
- }
-
- //------------------------------------------------------------------------------
- // ODUndo::ClearRedoHistory
- //------------------------------------------------------------------------------
-
- SOM_Scope void SOMLINK ODUndoClearRedoHistory(ODUndo *somSelf, Environment *ev)
- {
- ODUndoMethodDebug("ODUndo","ODUndoClearRedoHistory");
- ODUndoData *somThis = ODUndoGetData(somSelf);
-
- SOM_CATCH
- return;
-
- if (_fSystemUndo)
- _fSystemUndo->ClearRedoHistory();
- }
-
- //------------------------------------------------------------------------------
- // ODUndo::PeekUndoHistory
- //------------------------------------------------------------------------------
-
- SOM_Scope ODBoolean SOMLINK ODUndoPeekUndoHistory(ODUndo *somSelf, Environment *ev,
- ODPart** part,
- ODActionData* actionData,
- ODActionType* actionType,
- ODName* actionLabel)
- {
- ODUndoMethodDebug("ODUndo","ODUndoPeekUndoHistory");
- ODUndoData *somThis = ODUndoGetData(somSelf);
-
- SOM_CATCH
- return kODFalse;
-
- if (_fSystemUndo)
- return _fSystemUndo->PeekUndoHistory(part, actionData, actionType,
- actionLabel);
- else
- return kODFalse;
- }
-
- //------------------------------------------------------------------------------
- // ODUndo::PeekRedoHistory
- //------------------------------------------------------------------------------
-
- SOM_Scope ODBoolean SOMLINK ODUndoPeekRedoHistory(ODUndo *somSelf, Environment *ev,
- ODPart** part,
- ODActionData* actionData,
- ODActionType* actionType,
- ODName* actionLabel)
- {
- ODUndoMethodDebug("ODUndo","ODUndoPeekRedoHistory");
- ODUndoData *somThis = ODUndoGetData(somSelf);
-
- SOM_CATCH
- return kODFalse;
-
- if (_fSystemUndo)
- return _fSystemUndo->PeekRedoHistory(part, actionData, actionType,
- actionLabel);
- else
- return kODFalse;
- }
-
- //------------------------------------------------------------------------------
- // ODUndo::AbortCurrentTransaction
- //------------------------------------------------------------------------------
-
- SOM_Scope void SOMLINK ODUndoAbortCurrentTransaction(ODUndo *somSelf, Environment *ev)
- {
- ODUndoMethodDebug("ODUndo","ODUndoAbortCurrentTransaction");
- ODUndoData *somThis = ODUndoGetData(somSelf);
-
- SOM_CATCH
- return;
-
- if (_fSystemUndo)
- _fSystemUndo->AbortCurrentTransaction();
- }
-
-